refactoring ui
2022-12-12 · 34 min read
a minimal summary.
example systems #
font size #
- 12px
- 14px
- 16px
- 18px
- 20px
- 24px
- 30px
- 36px
- 48px
- 60px
- 72px
paddings, margins, sizes #
- 4px
- 8px
- 12px
- 16px
- 24px
- 32px
- 48px
- 64px
- 96px
- 128px
- 192px
- 256px
- 384px
- 512px
- 640px
- 768px
shadows #
box-shadow: 0 1px 3px hsla(0,0%,0%,.12), // z-level +1
0 1px 2px hsla(0,0%,0%,.24);
box-shadow: 0 3px 6px hsla(0,0%,0%,.15), // z-level +2
0 2px 4px hsla(0,0%,0%,.12);
box-shadow: 0 10px 20px hsla(0,0%,0%,.15), // z-level +3
0 3px 6px hsla(0,0%,0%,.10);
box-shadow: 0 15px 25px hsla(0,0%,0%,.15), // z-level +4
0 5px 10px hsla(0,0%,0%,.10);
box-shadow: 0 20px 40px hsla(0,0%,0%,.20); // z-level +5fonts #
headlines #
- proxima nova (head: bold 48px, sub: regular 24px, button: bold 20px)
- freight sans (head: bold 48px, sub: proxmia nova 24px, button: proxima nova bold 20px)
- futura (head: bold 36px, sub: trade gothic next regular 24px, button: trade gothic next bold 20px)
- harmonia sans (head: black 48px, sub: graphik regular 24px, button: graphik semibold 20px)
- graphik (head: black 48px, sub: regular 24px, button: semibold 18px)
- ff meta serif (head: serif bold 48px, sub: myriad pro regular 24px, button: myriad pro semibold 20px)
- roboto (head: black 48px, sub: regular 24px, button: bold 20px)
- jubilat (head: semibold 48px, sub: proxima nova 24px, button: proxima nova bold 20px)
- interstate (head: bold 48px, sub: light 24px, button: regular 20px)
- neue plak (head: extra black 48px, sub: regular 24px, button: bold 20px)
- adelle (head: extra bold 48px, sub: proxima nova regular 24px, button: proxima nova bold 20pxhttps://fonts.google.com/specimen/Lexend)
application UI #
- proxima nova
- inter UI
- roboto
- graphik
- source sans
- lato
- avenir next
- open sans
- aktiv grotesk
- benton sans
- soleil
- camphor
- neue plak text
- effra
articles #
- freight text (title: sans book 48px, body: text book 18px, meta: sans book 16px)
- source sans (title: sans light 48px, body: sans regular 18px, meta: sans regular 16px)
- open sans (title: sans light 48px, body: sans regular 18px, meta: sans regular 16px)
- merriweather (title: sans 16px, body: serif light 16px, meta: sans 14px)
- proxima nova (title: freight sans bold 48px, body: regular 18px, meta: regular 16px)
- franklin gothic (title: demi 48px, body: book 18px, meta: book 16px)
- camphor (title: light 48px, body: regular 18px, meta: regular 16px)
starting from scratch #
start with a feature, not a layout #
don't start by designing the sidebar. don't start with the shell.
start with an actual piece of functionality. start with a feature like "first start up", "recovery flow", "outbound payment", "new inbound payment notification".
detail comes later #
don't get hung up on low-level decisions like typefaces, shadows, icons, ...
one trick: design on a paper using a thick sharpie. you can quickly cover many layouts without getting lost in the weeds.
start by designing in grayscale. this forces spacing, contrast, and size to do all the heavy lifting.
avoid over-investing early on so you can move fast and explore the design space fast.
don't design too much #
- don't worry about how every feature interacts. design one or two features and then try implementing them.
work in cycles #
once you're happy with the basic design, make it real.
iterate on the implementation until there are no big problems left, then jump back into design mode and work on the next feature.
be a pessimist #
don't imply functionality you aren't ready to build yet.
design the smallest useful version you can feasibly ship right now.
if a feature is "nice-to-have", design it later.
choose a personality #
- if you don't have a gut feeling on what personality you're going for, just
stealimprove on what your competitors are doing : ) - ex: bank: secure, professional, trustworthy
- ex: trendy startup: fun, playful
- font choice plays a huge role in determining personality.
- serif: elegant and classy
- ex: Freight Text
- rounded sans: playful
- ex: Proxima Soft
- neutral sans: plain (rely on other elts for personality)
- ex: Freight Sans
- serif: elegant and classy
- color:
- blue: safe and familiar; no one complains about blue
- gold: expensive and sophisticated
- pink: fun and not serious
- border radius: (avoid mixing different border radii)
- none: serious and formal
- small: neutral
- large: playful
- language:
- impersonal tone: official and professional
- casual or friendly tone: ... friendly
limit your choices #
avoid wasting time over minor design choices, like 12px vs 13px, 10% vs 15% opacity, bold vs semibold, etc...
define systems in advance: choose 8-10 primary shades ahead of time. choose a few standard font sizes (12px, 16px, 24px, 32px).
this trick lets you "design by elimination" since there far fewer correct choices with a well-constrained design system.
the more systems you have in place, the faster you can work. choose systems for:
- font size
- font weight
- line height
- color
- margin
- padding
- width
- height
- box shadows
- border radius
- border width
- opacity
you also don't need to define all this ahead of time. have a systems-focused mindset while you're designing. look for opportunities to systematize.
hierarchy is everything #
not all elements are equal #
visual hierarchy is how important each interface element is, relative to each other.
a UI will feel noisy and cluttered when there is poor visual hierarchy; if everything is competing for attention, it's not clear what actually matters.
deliberatley de-emphasize secondary information. intentionally highlight elements that are most important.
size isn't everything #
don't over-rely on font size to control your hierarchy. this leads to primary content that is too large and secondary content that is too small.
look to leverage font weight or font color in addition to font size to communicate hierarchy.
stick to around three colors: (1) a dark color for primary content, (2) a grey for secondary content, (3) a lighter grey for teriary content.
and two font weights: (1) a normal font weight 400-500 and (2) a heavier font weight 600-700.
font weights under 400 are usually too hard to read for UI work.
don't use grey text on colored backgrounds #
grey on colored backgrounds doesn't look great. what grey text on white backgrounds actually accomplishes is reduced contrast.
neither should you just reduce the opacity; the font will still look dull.
instead, choose a new color specifically for this background. just choose the same hue and adjust the saturation and lightness until it looks right.
emphasize by de-emphasizing #
sometimes the main element just isn't standing out. everything you do to emphasize just doesn't give it enough "pop".
in this situation, instead of further emphasizing the main element, figure out how to de-emphasize the elements around it.
example: if a sidebar feels like it's competing with the main content, let it sit directly on the background.
labels are a last resort #
when displaying data, avoid falling into the trap of displaying it in a naive label: value format. these blocks often lack hierarchy since every piece of data is given equal emphasis.
sometimes the format is enough #
often the format and context is enough, like guy@bigcorp.com is an email, or (555) 412-4566 is a phone number, or $19.99 is a price.
when you avoid unnecessary labels, it's much easier to establish hierarchy, making the interface feel more designed.
use clarifying text #
one trick: instead of using a label like "in stock: 12", try adding clarifying text like "12 left in stock". another example: avoid "bedrooms: 12", use "12 bedrooms".
labels are secondary #
on a dashboard, you might have multiple pieces of similar data that need to be easily scannable.
in these situations, add a label but treat it as supporting content and de-emphasize it relative to the actual data content.
when to emphasize a label #
in a situation like an information dense tech-specs page, where a user will be actively scanning for the label, the reverse should apply: emphasize the label instead of the data.
separate visual hierarchy from document hierarchy #
when designing for the web, it's necessary to assign semantic tags like h1, h2, ... to programmaticly communicate hierarchy to search engines and indexers.
however, avoid this trap: don't couple the visual hierarchy with the semantic document hierarchy.
usually it's the content that should be in focus, not the title. give the title an h1 tag, but change the styling so it's actually de-emphasized.
in the extreme, add section titles to the markup but completely hide them visually because the content stands for itself.
balance weight and contrast #
bold text feels emphasized because it covers more surface area.
this applies to other UI elements as well.
use contrast to compensate for weight #
assume you have two elements with different weights. how do you get them "balanced", so they feel they have the importance? we do this by reducing the contrast of the heavier element.
this principle is especially applicable to icons, as it's not possible to increase the weight of an icon. instead, we de-emphasize an icon by lowering its contrast and giving it a softer color.
use weight to compensate for contrast #
in the reverse, increasing weight is a good way to emphasize low contrast elements.
this is especially useful for things like 1px borders that are too subtle with a soft color but make the design feel cluttered when darkening the color. instead of changing the color, increase the weight. make it a 2px border instead of a 1px border.
semantics are secondary #
when there are multiple actions on a page (e.g., add, edit, delete), don't design those actions based purely on semantics (e.g., green add, red delete).
don't make all your buttons the same size and only vary the color. they are NOT all the same importance!.
always remember the visual hierarchy; more important actions should be more prominent.
most pages only have one or two primary actions, a couple less important secondary actions, and a few seldom-used tertiary actions.
- primary actions should be obivous. try solid high contrast background colors here.
- secondary actions should be clear but not prominent. try outline styles or lower contrast background colors with these.
- tertiary actions should be discoverable but not unobtrusive. styling these like links works well.
just because an action is destructive doesn't mean it needs a big red all-up-in-your-face button. if it isn't the primary action, then don't style it as such.
layout and spacing #
start with too much whitespace #
an easy way to clean up a design is to just give every element a little more room to breath.
whitespace should be removed, not added #
it's much easier to get a good look if you remove whitespace from a design that has too much than if you add whitespace to something that has too little.
usually adding whitespace ends up with something that has the bare minimum to not look actively bad.
usually a design that feels like it has "a little too much" whitespace, when focused on designing a specific component, actually has "just enough" whitespace when placed into a complete UI.
desnse UIs have their place #
UIs with lots of space usually look cleaner and simpler, but there are absolutely situations where you need a lot of information on screen at once.
be deliberate about density. it's much more obvious when you need to remove space than when you need to add it.
establish a spacing and sizing system #
don't nitpick about 120px vs 125px for each element in your UI.
be systematic; choose a limited set of values in advance and use them consistently.
you'll notice that you can design much, much faster. your layouts will also look much more consistent.
a linear scale won't work #
don't use something like "make sure everything is a multiple of 4px".
small size deltas at small scales can have a huge impact, like for icons or paddings inside a button.
but an extra 4px vs 8px width is imperceptible for a big 500px wide card.
make sure no two values in your scale are ever closer than ~25%.
example system #
- 4px
- 8px
- 12px
- 16px
- 24px
- 32px
- 48px
- 64px
- 96px
- 128px
- 192px
- 256px
- 384px
- 512px
- 640px
- 768px
you don't have to fill the whole screen #
if you only need 600px, use 600px. don't make things unnecessarily wide.
shrink the canvas #
if you're building a responsive mobile web app, try starting with a ~400px canvas.
once you have something decent, try bringing it onto a larger screen and add anything that felt like a compromise for the smaller screen.
thinking in columns #
if you've designed something that works well for a narrower screen, but feels unbalanced in a wider UI, try splitting it into columns instead of making it wider.
grids are overrated #
using a 12-column grid is a great way to simplify layout decisions, but outsourcing all of your layout to the grid can do more harm than good.
not all elements should be fluid #
a grid is about giving elements fluid, %-age based widths. usually each column is about 8.33% wide.
however, there are a lot of situations where it makes more sense for an element to have a fixed width.
for example, if you try to use a grid system with a typical sidebar + main content screen, things will break down when you try to resize the screen; the sidebar will end up looking squished or too wide.
instead, give the sidebar a fixed width. the main content can use its own internal grid if it needs.
don't use percentages unless you actually want it to scale.
don't shrink an element unless you need to #
don't: give a login form 6 cols for small screens, 8 cols for medium screens, 10 cols for big screens.
do: if you know 500px is the optimal size for the card, then just set the max-width to 500px and only force the elements to shrink below that width.
don't be a slave to the grid; give components the space they need and don't make compromises until it's actually necessary.
relative sizing doesn't scale #
it might be tempting to describe sizes in subcomponents relative to their parent component, however this doesn't actually work that well for different screen sizes.
ex: an article might use an 18px body font size and then try to define the heading as 2.5 em (relative to the article body font size), so about 46px. however, this will look too large on a mobile screen. a better mobile screen would use 14px body font size and then 24 px heading font size; only a 1.5-1.7x difference!
in general: elements that are large on large screens will shrink faster than elements that are already fairly small. the difference in size b/w elements on smaller screens should be smaller.
relationships within elements #
this principle, that sizing should happen independently for different screen sizes, also applies to properties within a single component.
ex: you have a button with 16px font size, 16px horizontal padding, and 12px of vertical padding.
just like before, it's tempting to define the two paddings as (linear) dependent variables on the font size; however, this doesn't actually look that good in practice.
instead, the button's padding needs to get tighter as the font size decreases.
give yourself the freedom to fine-tune things independently for different contexts.
avoid ambiguous spacing #
one reason why visible separators (border lines, horizontal bars, etc...) are so easy to fallback on, is that they make it obvious which elements belong to which groups.
however, visible separators also contribute greatly to visiual clutter. but, without a visible separator, it's not always obvious.
especially avoid e.g. equal margin above and below a label. increase the margin above and decrease the margin below to more clearly "group" the label with the field.
another ex: avoid bulleted lists where each line has equal vertical space; it can be confusing when skimming which line belongs to which bullet point. instead, increase spacing between bullet groups to give unambiguous visual separation.
whenever you're relying on spacing to connect a group of elements, always make sure there's more spacing around the group that there is within it.
designing text #
establish a type scale #
most interfaces use too many font sizes.
for teams without a rigid design system, it's not uncommon for the UI to use every font size pixel value between 10px and 24px somewhere.
not using a type system is a bad idea because (1) the design usually looks inconsistent and (2) it slows you down.
choosing a scale #
just like layout and spacing, using a linear scale won't work.
avoid some mathematical system and instead use something like:
- 12px
- 14px
- 16px
- 18px
- 20px
- 24px
- 30px
- 36px
- 48px
- 60px
- 72px
don't use em (relative to parent element font size) to define the sizes. stick to px or rem (relative to global document font size).
use good fonts #
understanding which details make a good or bad font takes years. without years,
play it safe #
for UI design, the safest bet is a fairly neutral sans-serif like Helvetica.
if you don't trust your taste, use the system font stack: -apple-system, Segoe UI, Roboto, Noto Sans, Ubuntu, Cantarell, Helvetica Neue;.
ignore typefaces with less than five weights #
a good heuristic is to ignore typefaces with only a few weights. typefaces with more weights tend to be more carefully crafted.
an easy trick is to search on e.g. Google Fonts and filter out all fonts with less than 10 weights.
optimize for legibility #
fonts are usually designed for a specific purpose.
fonts for headlines usually have tighter letter spacing and shorter x-heights.
fonts for smaller sizes usually have wider letter spacing and taller x-heights.
avoid choosing a headline font for your main UI text.
trust the wisdom of the crowds #
when starting out, pick popular fonts.
steal fonts from sites and apps you admire.
keep your line length in check #
- line length should be 45-75 characters or 20-35 em
paragraphs: don't fit your text to your layout. strive to create the best reading experience.
make your paragraphs wide enough to fit 45-75 characters per line. usually about 20-35 em.
baseline not center #
- align text by font baseline
when you have multiple font sizes in the same "row", align by the font baseline, not the center.
line-height is proportional #
first: why do we even have space b/w lines? so it's easier for readers to find the start of the next line when the text wraps.
if you ever find yourself skipping a line or re-reading the same line, the line-height is probably too short.
line-height vs text width #
- narrower lines => less line-height
- longer lines => greater line-height
longer lines need greater line-height.
ex: narrow, short paragraphs can get away with 1.5 line-height, while wider content might need 2.0 line-height.
line-height vs font size #
- smaller font => greater line-height
- larger font => less line-height
larger fonts need less line-height.
ex: small body text uses 1.75 line-height vs article heading uses 1.0 line-height.
not every link needs a color #
when links are included in a block of normal text, it's important that they stand out as links and look clickable.
but if almost every element on the screen is a link, then the extra "pop" from link-styling can be overbearing.
instead emphasize links more subtly, like with a darker color or heavier font.
some links might not even need emphasis, like for tertiary elements. these can be styled only on hover.
align with readability in mind #
for nearly all languages (except right-to-left like Arabic), text should be left-aligned, since you read left-to-right.
short independent blocks of text, like headlines or marketing boxes, can often look good center aligned. however, don't center align if text is longer than 2-3 lines.
numbers and prices in tables should be right aligned so the decimal is always in the same place.
justified text often looks good in print and may work on the web when you want a more formal look. when using justified text remember to hyphenate text to avoid awkward gaps b/w words.
use letter-spacing effectively #
as a general rule, you should usually leave letter-spacing to the font typeface designer.
some specific cases where tweaking the letter-spacing works well:
tightening headlines #
- body typeface for headline => tighten letter-spacing
- avoid headline typefaces for body text
different fonts are usually designed for different purposes. ex: Open Sans is designed for body text while Oswald is designed for headings.
if you use a body text typeface for a headline, probably tighten the letter-spacing.
improving all-caps legibility #
- all-caps => widen the letter-spacing
typefaces are usually optimized for normal sentences. when using all-caps, probably widen the letter-spacing.
working with color #
ditch hex for HSL #
hex colors that have a lot in common look nothing alike in code.
Lightness in HSL slides from 0% (black) to 100% (white). 50% is "full" saturation.
HSL is not the same as HSB. in HSB, 0% brightness is always black (like HSL), but 100% is not always white; only if the saturation is also 0%.
HSB is more common in design software, but browsers only understand HSL.
you need more colors than you think #
palette generators that spit out 5 colors are not super useful. a site designed with just those 5 colors will look awful and over-saturated.
a good color palette has three main components: greys, primaries, and accents.
greys #
text, backgrounds, panels, form controls -- almost everything is grey. you'll want lots of greys too; between 8-10 shades.
true blacks also tend to look unnatural; start with a really dark grey.
primaries #
most sites need just one, maybe two colors used for primary actions, active navs. these colors determine the overall look of a site. like how FB is "blue".
just like greys, you'll want 5-10 primary shades.
accent colors #
every site needs a few accent colors for communicating different things. new features might use an eye-popping yellow, pink, or teal. destructive actions might use reds. warnings might use yellows. positive trends might use greens.
it's not uncommon to need as many as 10 different colors, with 5-10 shades each for a complex UI.
define your shades up front #
avoid: css functions like lighten or darken. you'll end up with 35 slightly different blues that all look the same.
you'll be a lot faster if there are only a few shades to choose from.
building the shades for a color #
- choose the base color first. this is the color in the "middle" that the lighter and darker shades are based on. rule of thumb: choose a color that would make a good button background.
- find the darkest and lightest shades. the darkest shade is usually reserved for text while the lightest is often a background shade. these will usually have the same or similar hue as the base color. rule of thumb: build a simple alert box w/ lightest shade as background and darkest shade as text.
- fill the gaps. start your scale with 100 -> 500 -> 900 for lightest -> base -> darkest. fill the gaps with 300 and 700, which should feel like perfect middle grounds between their neighbors. if you need more colors, do the same with 200, 400, 600, and 800.
what about greys? #
for greys, the base color isn't as important. regardless, the process isn't the same.
it's not a science #
trust your eyes.
unfortunately you can't just lerp between 10 and 90 lightness to build the scale. the systematic approach is a good place to get started, but you'll probably have to make tweaks to get the perceived scale correct.
don't let lightness kill your saturation #
in HSL color space, saturation has a diminishing impact as lightness approaches 0 or 100. if you don't want the lighter and darker shades to look washed out, you'll need to increase the saturation as you get further away from 50.
but what if your base color is already heavily saturated? how do you increase the saturation if it's already at 100?
use perceived brightness to your advantage #
if you put two max-saturation colors side by side, a yellow H=60 and a blue H=240 with S=100 and L=50, you'll notice the yellow looks much brighter than the blue. this is because certain hues have a greater perceived brightness than others.
there's a handy formula that takes an RGB color and outputs the perceived brightness.
$$ p(r, g, b) := \frac{\sqrt{0.299 , r^2 + 0.587 , g^2 + 0.114 , b^2}}{255} $$
in the above, note that $r, g, b \in [0,255]$.
plugging in some simple cases, we can see that all black has the lowest brightness, $p(0, 0, 0) = 0$; and all white has the highest, $p(255, 255, 255) = 1$.
in some sense, the formula is telling us that pure blue and pure red have low perceived brightness; while colors like yellow (r+g), cyan (g+b), and magenta (r+b) have high perceived brightness.
these high perceived brightness peaks are located at 60 (yellow), 180 (cyan), and 300 (magenta).
changing brightness by rotating hue #
instead of increasing the lightness to increase the brightness, which often loses some of the color's intensity, you can also rotate its hue towards the nearest brightness peak (60, 180, 300).
if you want to make it darker, rotate it towards the nearest dark hue: 0 (red), 120 (green), 240 (blue).
this technique is especially useful when creating a palette for a light color like yellow. instead of just decreasing the lightness (and turning into a muddy and dull brown), gradually rotate the hue towards more of an orange as you decrease the brightness.
best in small doses: avoid rotating the hue more than 20-30 deg or it'll look like a totally different color.
greys don't have to be grey #
true grey has no saturation (rather 0 or 100 doesn't make a different).
in practice however, we often use "cool" or "warm" greys. these have a bit of saturation with some yellow or orange for "warm" and blue for "cool".
remember to increase the saturation for your greys as they get darker/lighter.
accessible doesn't have to mean ugly #
design guidelines recommend a contrast ratio of 4.5 : 1 for <18px body text and 3 : 1 for larger text.
this is fairly easy to achieve for standard dark text on light background, but significantly more complicated when working with color.
flipping the contrast #
when using white text on a colored background, you'll need surprisingly dark background colors to meet the 4.5 : 1 ratio. so dark that it'll interfere with the visual hierarchy.
instead, try flipping the contrast. rather than light text on dark colored background, try dark text on light colored background. this way the color is way less in-your-face.
rotating the hue #
even harder than white text on a colored background is colored text on a colored background, especially for secondary text that needs to be de-emphasized.
you'll find that it's very hard to avoid pure white while meeting accessibility requirements if you just change the lightness and saturation.
instead, rotate the hue towards a brighter color (yellow, cyan, magenta) while also ramping up the saturation and lightness.
don't rely on color alone #
color should supplement and enhance information, but it shouldn't be the only source.
in the extreme case, near-blind or color blind users will have a hard time interpreting your UI.
consider also users with low screen brightness, users using a red-shift application like f.lux, or users with their phone set to greyscale for power saving or late-night reading.
for a top-level metric graph, don't just use red or green to indicate the trend. also add an up- or down-arrow.
for a pie-graph where each color corresponds to a different category, consider using just different contrasts for each category.
creating depth #
emulate a light source #
notice how some elements feel like they're raised off the page while others feel inset into the background.
creating this effect requires understanding just one simple rule:
light comes from above #
when you shine light down from above (coming from a light source like the sun or a room's ceiling lamp), things look raised or inset depending on the shadows they create.
for raised elements, the top edge gets the most light while the bottom edge gets the least light.
in contrast, for inset elements, the top edge gets the least light while the bottom edge gets the most light.
simulate light in a user interface #
if you want an element to appear raised or inset, first figure out what profile you want the element to have on the page, as if it were a piece of cardboard resting on the page itself.
- how high is the block?
- what is it resting on?
- what do the edges look like? are the straight square edges or are they beveled?
since most people look slightly down at their screens, the most natural look reveals a bit of the top edge and hides the bottom edge.
add a top edge with an inset box shadow of maybe 1-2px and a lighter color. choose the lighter color by hand instead of just using lighten, which will suck out all the saturation.
then give it a small dark box shadow with a slight vertical offset (you only want the shadow below the element). the offset should only be a few pixels.
finally: don't get carried away. too many shadows and insets can make the UI look busy and cluttered.
use shadows to convey elevation #
shadows can be more than just a flashy visual effect -- use them thoughtfully to convey visual hierarchy by placing elements on a virtual Z-axis, with more important elements closer to the user.
small shadows with a tight blur radius feel only slightly raised while large shadows with a higher blur radius feel closer.
you might use a small shadow for a button, where you want it to be noticable but not dominant. ex: box-shadow: 0 1px 3px hsla(0,0%,0%,0.2).
medium shadows are useful for dropdowns or other elements that need to sit "on top" of the rest of the UI. ex: box-shadow: 0 4px 6px hsla(0,0%,0%,0.1)
large shadows are great for modal dialogs, where you really want to capture the user's attention. ex: box-shadow: 0 15px 35px hsla(0,0%,0%,0.2).
establish an elevation system #
just like typography, color, spacing, and sizing; define a fixed set of shadows / z-levels ahead of time to speed up your workflow and maintain consistency.
start with the smallest and largest shadows, then fill in linearly. you probably only need 5 shadows max.
- z-level +1:
box-shadow: 0 1px 3px hsla(0,0%,0%,.2) - z-level +2:
box-shadow: 0 4px 6px hsla(0,0%,0%,.2) - z-level +3:
box-shadow: 0 5px 15px hsla(0,0%,0%,.2) - z-level +4:
box-shadow: 0 10px 24px hsla(0,0%,0%,.2) - z-level +5:
box-shadow: 0 15px 35px hsla(0,0%,0%,.2)
combining shadows with interaction #
shadows work great in combination with user interaction: make a table entry hover up a bit when the mouse hovers. have a button move down a z-level on click.
think about items moving up or down a z-level on interaction rather than nitpicking about precise shadow values.
shadows can have two parts #
you'll often need two shadows: one cast by direct light and one cast by ambient light.
box-shadow: 0 4px 6px hsla(0,0%,0%,.7), // ambient shadow
0 5px 15px hsla(0,0%,0%,.1); // direct shadow
the first shadow is larger and softer, with considerable vertical offset and large blur radius. it simulates the shadow cast behind an object by a direct light source.
the second shadow looks tighter and darker, with a smaller vertical offset and blur radius. it simulates the dark areas immediately underneath a lit object where ambient light has trouble reaching.
that second, ambient light shadow helps make the element's edges nice and defined, while letting the overall shadow stay nice and subtle.
accounting for elevation #
as an object gets farther from the surface, the small dark ambient shadow slowly disappears.
make sure to account for this and make the ambient shadow more and more subtle as the z-level increases.
try these:
box-shadow: 0 1px 3px hsla(0,0%,0%,.12), // z-level +1
0 1px 2px hsla(0,0%,0%,.24);
box-shadow: 0 3px 6px hsla(0,0%,0%,.15), // z-level +2
0 2px 4px hsla(0,0%,0%,.12);
box-shadow: 0 10px 20px hsla(0,0%,0%,.15), // z-level +3
0 3px 6px hsla(0,0%,0%,.10);
box-shadow: 0 15px 25px hsla(0,0%,0%,.15), // z-level +4
0 5px 10px hsla(0,0%,0%,.10);
box-shadow: 0 20px 40px hsla(0,0%,0%,.20); // z-level +5even flat designs can have depth #
"flat design" avoids shadows, gradients, or other effects that try to mimic how light interacts with things irl.
but the most effective flat designs still convey depth, just in a different way.
creating depth with color #
in general (esp. w/ shades of the same color), lighter objects feel closer and darker objects feel farther away.
make an element lighter than its background color to make it feel like it's raised off the page. likewise, make an element darker if you want it to feel inset like a well.
using solid shadows #
with a flat design, you can also use a short solid shadow with no blur radius. this can help a card or button stand out without losing the flat aesthetic.
overlap elements to create layers #
an effective tool at creating depth: overlap different elements. this makes the design feel like it has multiple layers.
ex: instead of a card fully encompassed by a bg, followed by the next section, consider placing the card on the boundary between the two sections.
ex: make an element taller than its parent so it overlaps boths sides.
ex: overlap the <- and -> buttons on the edges of a carousel.
overlapping images (like profile pic on bg pic) can also work great, but requires a little care to avoid overlapping images clashing.
one simple trick is to add an "invisible border" that matches the card's background color, so there's always a gap between images.
working with images #
use good photos #
bad photos will ruin a design, even if the UI is great.
if you need photos, either: (1) hire a professional, or (2) use high quality stock photos.
don't expect to design with placeholders and then just use some shit photos you took on your phone.
text needs consistent contrast #
text on top of an image rarely works well without changes. you might find that regardless of the text color the text is still unreadable.
try adding a semi-transparent overlay, maybe 50% black, to make the contrast more consistent.
try lowering the contrast or increasing the brightness of the image itself.
try colorizing the image (lower the contrast, desaturate to grayscale, then add a solid fill color in "multiply" blend mode). this can also make the image pair well with your existing brand colors.
try adding text shadow, probably in combination with one of the previous tricks.
everything has an intended size #
broadly: almost all assets (icons, fonts, photos) are intended to be at a specific size. straying from the intended size often looks bad.
ex: obviously rasterized images don't scale well at all and just look blurry and pixelated.
don't scale up icons #
while vector icons won't look blurry and pixelated, they always feel disproportionately "chunky" when you scale them up. you'll likely have to find a version drawn specifically for larger proportions.
if you've only got small icons, try enclosing them in a larger shape and giving the shape a background color.
don't scale down icons either #
icons meant for larger sizes look choppy and fuzzy when you squish them down.
instead draw a super simplified version of the logo at the target size.
don't scale down screenshots #
if you take a full-size screenshot and shrink it 70% to make it fit, you'll end up with something busy and illegible.
instead try taking a screenshot at your phone or tablet layout and save space in the design so you don't have to squish the image as much.
try also a partial screenshot so you can display it more consistently without needing to scale down.
try also redrawing a heavily simplified version of the UI, with details removed and small text replaced with simple lines.
beware user-uploaded content #
when using user-uploaded images you don't have the luxury of fine-tuning the contrast, colors, and crop.
to recover some control and keep the design clean:
control the shape and size #
avoid showing user images at their original shape and size. lots of different sizes can really throw off a layout.
to do this use background-size: cover to keep images at a predefined shape.
prevent background bleed #
when a user uploads an image with a background color the same as the UI background, the elements bleed together and lose shape.
try using a subtle inner shadow. hard borders will often clash with colors in the image.
finishing touches #
supercharge the defaults #
you don't always have to add new elements to add flare, supercharge what is already there.
ex: if you have a bulleted list, replace the bullets with icons.
ex: if you have a testimonial, "promote" the quotes to visual elements by increasing the size and changing the color.
ex: use custom checkboxes and radio bottons with your brand colors
add color with accent borders #
if you're not a graphic designer who can make illustrations or take photos, you can add a quick dash of visual flair by just adding some colorful accent borders to bland parts of your UI.
ex: top of a card, under/over active navigation items, alongside an alert message, underneath a headline, or across the whole layout.
change the background color #
one easy way to upgrade a design is to change the background color of an element, or for whole sections.
you can even use a slight gradient, though take care the two hues are no more than 30deg apart.
use a repeating pattern #
try adding a subtle repeating background to the background, or just across one edge.
keep contrast low so it doesn't interfere with the content.
add a simple shape or illustration #
instead of decorating an entire background, try adding a simple shape or illustration in one or two specific positions. simple geometric shapes work well.
don't overlook the initial state #
you've finished designing a feature and it looks great when filled out with content. but what does it look like when a new user opens it? if it's completely barren and empty, that's not a great look.
empty states are a user's first interaction with a new product or feature. use them as an opportunity to be interesting and exciting; not plain or boring.
if you're designing something that depends on user content, the empty state should be a priority, not an after thought.
try: adding an illustration or call-to-action on the empty page to encourage the user to take the next step.
if there are a bunch of other supporting UI like tabs or filters, consider completely hiding them. all the extra stuff has no point if there's no content.
use fewer borders #
when you need to create separation b/w elements, resist the temptation to immediately reach for a border.
using too many can make your design busy and cluttered.
try: using a box shadow to outline an element like a border, but more subtly.
try: using two different background colors b/w adjacent elements to create distinction.
try: adding extra spacing between elements.
think outside the box #
get creative. reconsider preconceived notions you have about different elements.
ex: instead of a boring white-background dropdown of vertical links, add some columns, add some images, add supporting text. keep it interesting!
ex: there's nothing more boring than a stack of radio buttons. try making a row of selectable cards instead.
leveling up #
look for decisions you wouldn't have made #
whenever you come across a design you really like, ask yourself: "did the designer do anything here I would never have thought to do?"
"why did they use an inverted background color on the date picker?"
"why did they place the button inside the text input instead of on the outside?"
"why did they use two font colors in the headline?"
reproduce a design from scratch #
the best way to notice the little details is to reproduce a design from scratch, without looking at the developer tools. you'll pick up all the little details and hidden tricks that you wouldn't have otherwise noticed.